#pragma once
#include <iostream>
#include <string>
#include <memory>
#include "Socket.hpp"
#include "epoller.hpp"
#include "Log.hpp"

using namespace NetWorkModule;
using namespace EpollerModule;

const static int gbacklog = 32;

// for debug
std::string EventToString(uint32_t events)
{
    std::string info;
    if (events & EPOLLIN)
        info += "EPOLLIN ";
    if (events & EPOLLOUT)
        info += "EPOLLOUT ";
    if (events & EPOLLET)
        info += "EPOLLET";

    return info;
}

class EpollServer
{
    static const int maxevents = 64;
public:
    EpollServer(int port)
    :_port(port), _epoller(new Epoller()), _listensock(new TcpSocket()), _isrunning(false) 
    {}
    bool InitServer()
    {
        // 1. 创建listensock
        _listensock->BuildListenSocketMethod((uint16_t)_port, backlog);
        lg.LogMessage(Info, "init socket success, listensock is : %d\n", _listensock->GetSockFd());
        // 2. 创建epoll模型
        _epoller->InitEpoller();
        lg.LogMessage(Info, "init epoll success~\n");
        // 3. 将listensock添加到epoll中
        _epoller->AddEvent(_listensock->GetSockFd(), EPOLLIN);
        return true;
    }
    bool Accepetor(std::string* peerip, uint16_t* peerport)
    {
        int sockfd = _listensock->AcceptConnection(peerip, peerport);
        if(sockfd < 0){
            lg.LogMessage(Warning, "accept error");
            return false;
        }
        _epoller->AddEvent(sockfd, EPOLLIN);
        return true;
    }
    int Recv(int sockfd, std::string* out)
    {
        char buffer[1024];
        int n = ::recv(sockfd, buffer, sizeof(buffer)-1,0);
        if(n > 0){
            buffer[n] = 0;
            *out = buffer;
        }
        return n;
    }
    void HandlerEvent(int n)
    {
        lg.LogMessage(Debug, "%d 个 events 已经就绪了\n", n);
        for(int i = 0; i < n; i++){
            lg.LogMessage(Debug, "ready fd: %d, Event is: %s\n",
                          _revs[i].data.fd, EventToString(_revs[i].events).c_str());
            int sockfd = _revs[i].data.fd;
            uint32_t events = _revs[i].events;
            if(events & EPOLLIN){
                //读事件有俩种，1.listensock 2.normal sockfd
                if(sockfd == _listensock->GetSockFd()){
                    std::string clientip;
                    uint16_t clientport;
                    if(!Accepetor(&clientip, &clientport))continue;
                    lg.LogMessage(Info, "accept client success, client[%s:%d]\n",
                                  clientip.c_str(), clientport);
                }else{
                    std::string message;
                    int n = Recv(sockfd, &message);//用户自定义回调函数
                    if(n > 0){
                        std::cout << "client# " << message << std::endl;
                        message.resize(message.size()-strlen("\r\n"));
                        // 直接写 -- TODO
                        std::string echo_message = "echo message: " + message + "\r\n";
                        send(sockfd, echo_message.c_str(), echo_message.size(), 0);
                    }
                    else
                    {
                        if (n == 0)
                        {
                            lg.LogMessage(Info, "client %d close\n", sockfd);
                        }
                        else
                        {
                            lg.LogMessage(Info, "client recv %d error\n", sockfd);
                        }
                        // epoll移除一个fd，这个fd必须是合法的fd，才能被正确移除
                        _epoller->DelEvent(sockfd);
                        ::close(sockfd);
                    }
                }
            }
        }   
    }
    void loop()
    {
        _isrunning = true;
        while(true)
        {
            _epoller->DebugFdList();
            int timeout = -1;
            int n = _epoller->Wait(_revs, maxevents, timeout);
            switch(n)
            {
            case 0:
                lg.LogMessage(Info, "no events happen, timeout\n");
                break;
            case -1:
                lg.LogMessage(Error,"client wait failed~\n");
                break;
            default:
                lg.LogMessage(Info, "event happend ... \n");
                HandlerEvent(n);
                break;
            }
        }
        _isrunning = false;
    }
private:
    //std::string _ip;
    bool _isrunning;
    uint16_t _port;
    epoll_event _revs[maxevents];
    std::unique_ptr<Epoller> _epoller;//
    std::unique_ptr<Socket> _listensock;
};